package edu.stanford.bmir.protege.web.client.ui.ontology.stkos.mapper.according;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import com.google.gwt.core.shared.GWT;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.gwtext.client.core.Function;
import com.gwtext.client.data.Node;
import com.gwtext.client.widgets.tree.TreeNode;

import edu.stanford.bmir.protege.web.client.project.Project;
import edu.stanford.bmir.protege.web.client.rpc.OntologyServiceManager;
import edu.stanford.bmir.protege.web.client.rpc.data.EntityData;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.common.UtilEntityType;
import edu.stanford.bmir.protege.web.client.ui.library.msgbox.MessageBox;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.GWTExtUtil;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.StkosPanelType;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.interfaces.StkosTreeNodeHighlightable;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.mapper.common.StkosMapperClassTreePanel;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.mapper.common.StkosMapperConstant;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.mapper.common.StkosMapperPropertyTreePanel;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.mapper.common.StkosMappingNoSearchUtil;
import edu.stanford.bmir.protege.web.client.ui.portlet.AbstractOWLEntityPortlet;
import edu.stanford.bmir.protege.web.shared.project.ProjectId;

/**
 * The portlet is responsible for displaying according project`s class or
 * attribute tree.
 * 
 * @author LWS
 * 
 */
@SuppressWarnings("unchecked")
public class StkosMapperAccordingProjectTreePortlet extends
		AbstractOWLEntityPortlet implements StkosTreeNodeHighlightable {

	private Project accordingProject;

	private StkosPanelType type;

	private StkosMapperClassTreePanel classTreePanel;

	private StkosMapperPropertyTreePanel propertyTreePanel;

	public StkosMapperAccordingProjectTreePortlet(Project project) {
		super(project);
	}

	@Override
	public Collection<EntityData> getSelection() {
		return null;
	}

	@Override
	public void reload() {
	}

	@Override
	public void onRefresh() {
		if (classTreePanel != null) {
			classTreePanel.refreshTreeNode(getSelectedTreeNode());
		}
		if (propertyTreePanel != null) {
			propertyTreePanel.refreshTreeNode(getSelectedTreeNode());
		}
	}

	@Override
	public void initialize() {
		setHeight(500);

		showPanel(StkosPanelType.CLASS_TREE);
	}

	public boolean isClassTreePanelActivity() {
		boolean f = false;
		if (classTreePanel != null && StkosPanelType.CLASS_TREE.equals(type)) {
			f = true;
		}
		return f;
	}

	public boolean isPropertyTreePanelActivity() {
		boolean f = false;
		if (propertyTreePanel != null
				&& StkosPanelType.PROPERTY_TREE.equals(type)) {
			f = true;
		}
		return f;
	}

	public StkosPanelType getActivityPanel() {
		return this.type;
	}

	protected void fireOnSelectionChangeEvent() {
		fireEvent(GWTExtUtil.EVENT_ONSELECTIONCHANGE);
	}

	protected void fireOnDblclickEvent() {
		fireEvent(GWTExtUtil.EVENT_ONDBLCLICK);
	}

	protected void addClassTreePanel() {
		if (accordingProject == null) {
			return;
		}
		classTreePanel = new StkosMapperClassTreePanel(accordingProject,
				getProject());
		if (classTreePanel == null) {
			return;
		}
		classTreePanel.addListener(GWTExtUtil.EVENT_ONSELECTIONCHANGE,
				new Function() {
					@Override
					public void execute() {
						fireOnSelectionChangeEvent();
					}
				});
		classTreePanel.addListener(GWTExtUtil.EVENT_ONDBLCLICK, new Function() {
			@Override
			public void execute() {
				fireOnDblclickEvent();
			}
		});
		add(classTreePanel);
		doLayout();
	}

	protected void addPropertyTreePanel() {
		if (accordingProject == null) {
			return;
		}
		propertyTreePanel = new StkosMapperPropertyTreePanel(accordingProject,
				getProject());
		if (propertyTreePanel == null) {
			return;
		}
		propertyTreePanel.addListener(GWTExtUtil.EVENT_ONSELECTIONCHANGE,
				new Function() {
					@Override
					public void execute() {
						fireOnSelectionChangeEvent();
					}
				});
		propertyTreePanel.addListener(GWTExtUtil.EVENT_ONDBLCLICK,
				new Function() {
					@Override
					public void execute() {
						fireOnDblclickEvent();
					}
				});
		add(propertyTreePanel);
		doLayout();
	}

	public TreeNode getSelectedTreeNode() {
		TreeNode treeNode = null;
		if (isClassTreePanelActivity()) {
			treeNode = classTreePanel.getSelectionModel().getSelectedNode();
		}
		if (isPropertyTreePanelActivity()) {
			treeNode = propertyTreePanel.getSelectionModel().getSelectedNode();
		}
		return treeNode;
	}

	public void setAccordingProject(Project accordingProject) {
		this.accordingProject = accordingProject;
		removeAll(true);
		classTreePanel = null;
		propertyTreePanel = null;
		showPanel(type);
	}

	protected void removeAllItems() {
		if (classTreePanel != null) {
			classTreePanel.hide();
		}
		if (propertyTreePanel != null) {
			propertyTreePanel.hide();
		}
	}

	public void showPanel(StkosPanelType type) {
		removeAll();
		removeAllItems();
		this.type = type;
		if (StkosPanelType.CLASS_TREE.equals(type)) {
			setTitle("参照本体类树");
			if (classTreePanel == null) {
				addClassTreePanel();
			} else {
				classTreePanel.show();
			}
		} else if (StkosPanelType.PROPERTY_TREE.equals(type)) {
			setTitle("参照本体属性树");
			if (propertyTreePanel == null) {
				addPropertyTreePanel();
			} else {
				propertyTreePanel.show();
			}
		} else {
			setTitle("参照本体树");
		}
		doLayout();
	}

	protected boolean equals(Project project) {
		boolean f = false;
		if (accordingProject == null && project == null) {
			f = true;
		}
		if (accordingProject != null && project != null) {
			if (accordingProject.getProjectId() != null
					&& project.getProjectId() != null) {
				if (accordingProject.getProjectId().getId() != null
						&& project.getProjectId().getId() != null) {
					if (accordingProject.getProjectId().getId()
							.equals(project.getProjectId().getId())) {
						f = true;
					}
				}
			}
		}
		return f;
	}

	public void searchMappingNo(Integer mappingNo) {
		if (accordingProject == null || accordingProject.getProjectId() == null) {
			MessageBox.showAlert("提示", "请选择一个参照本体!");
			return;
		}

		String projectName = accordingProject.getProjectId().getId();
		String refProjectName = getProjectId().getId();

		StkosTreeNodeHighlightable highlightable = StkosMapperAccordingProjectTreePortlet.this;

		UtilEntityType searchedValueType = null;
		if (isClassTreePanelActivity()) {
			searchedValueType = UtilEntityType.CLASS;
		} else if (isPropertyTreePanelActivity()) {
			searchedValueType = UtilEntityType.ANY_PROPERTY;
		}

		StkosMappingNoSearchUtil stkosMappingNoSearchUtil = new StkosMappingNoSearchUtil(
				projectName, refProjectName, highlightable, searchedValueType);
		stkosMappingNoSearchUtil.search(mappingNo);
	}

	@Override
	public Collection<EntityData> getHighlight() {
		Collection<EntityData> highlighs = new ArrayList<EntityData>();
		TreeNode root = null;
		if (isClassTreePanelActivity()) {
			root = classTreePanel.getRootNode();
		} else if (isPropertyTreePanelActivity()) {
			root = propertyTreePanel.getRootNode();
		}
		if (root != null) {
			loop(root, highlighs);
		}
		return highlighs;
	}

	protected void loop(TreeNode node, Collection<EntityData> highlighs) {
		if (highlighs == null) {
			highlighs = new ArrayList<EntityData>();
		}
		if (node == null) {
			return;
		}

		if (StkosMapperConstant.HASSTKOSMAPPERTREENODESELECTEDCLS
				.equals(node
						.getAttribute(StkosMapperConstant.HASSTKOSMAPPERTREENODESELECTEDCLS))) {
			EntityData entityData = (EntityData) node.getUserObject();
			if (entityData != null) {
				highlighs.add(entityData);
			}
		}

		if (node.getChildNodes() != null) {
			for (Node child : node.getChildNodes()) {
				loop((TreeNode) child, highlighs);
			}
		}
	}

	@Override
	public void setHighlight(Collection<EntityData> highlight) {
		removeHighlight(getHighlight());
		if (accordingProject == null || accordingProject.getProjectId() == null) {
			return;
		}
		if (highlight == null) {
			return;
		}
		if (highlight.isEmpty()) {
			return;
		}
		ProjectId projectId = accordingProject.getProjectId();
		AsyncCallback<List<EntityData>> cb = new AsyncCallback<List<EntityData>>() {
			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Error at finding path to root", caught);
			}

			@Override
			public void onSuccess(final List<EntityData> result) {
				if (result == null || result.size() == 0) {
					GWT.log("Could not find path in the tree");
					return;
				}
				Timer timer = new Timer() {
					int ind = 0;
					int len = 0;

					@Override
					public void run() {
						if (len >= Integer.MAX_VALUE) {
							this.cancel();
						}

						EntityData entityData = result.get(ind);
						TreeNode node = null;
						if (isClassTreePanelActivity()) {
							node = classTreePanel.getNodeById(entityData
									.getName());
						} else if (isPropertyTreePanelActivity()) {
							node = propertyTreePanel.getNodeById(entityData
									.getName());
						}
						if (node != null) {
							if (ind == (result.size() - 1)) {
								// Highlight the tree node.
								GWTExtUtil
										.setTreeNodeCls(
												node,
												StkosMapperConstant.STKOSMAPPERTREENODESELECTEDCLS);
								node.setAttribute(
										StkosMapperConstant.HASSTKOSMAPPERTREENODESELECTEDCLS,
										StkosMapperConstant.HASSTKOSMAPPERTREENODESELECTEDCLS);
								// Scroll the tree panel.
								if (isClassTreePanelActivity()) {
									classTreePanel.scrollTreeNodeVisible(node);
								}
								if (isPropertyTreePanelActivity()) {
									propertyTreePanel
											.scrollTreeNodeVisible(node);
								}
								this.cancel();
							} else {
								node.expand();
								ind++;
							}
						}
						len++;
					}
				};
				timer.scheduleRepeating(350);
			}
		};
		Iterator<EntityData> ite = highlight.iterator();
		while (ite.hasNext()) {
			EntityData entityData = ite.next();
			if (entityData == null) {
				continue;
			}
			OntologyServiceManager.getInstance().getPathToRoot(projectId,
					entityData.getName(), cb);
		}
	}

	@Override
	public void removeHighlight(Collection<EntityData> highlight) {
		if (highlight == null || highlight.isEmpty()) {
			return;
		}
		Iterator<EntityData> ite = highlight.iterator();
		while (ite.hasNext()) {
			EntityData entityData = ite.next();
			if (entityData != null && entityData.getName() != null) {
				TreeNode node = null;
				if (isClassTreePanelActivity()) {
					node = classTreePanel.getNodeById(entityData.getName());
				} else if (isPropertyTreePanelActivity()) {
					node = propertyTreePanel.getNodeById(entityData.getName());
				}
				if (node != null) {
					node.setAttribute(
							StkosMapperConstant.HASSTKOSMAPPERTREENODESELECTEDCLS,
							null);
					GWTExtUtil.removeTreeNodeCls(node,
							StkosMapperConstant.STKOSMAPPERTREENODESELECTEDCLS);
				}
			}
		}
	}

}
